# To change this template, choose Tools | Templates
# and open the template in the editor.

__author__="lustalov"
__date__ ="$Dec 22, 2009 1:54:45 PM$"

import re, time
import uuid
import vdsClient as vdsc
import basicVdsTest as vdst

STORAGE_TYPE_NFS     = 1
STORAGE_TYPE_FCP     = 2
STORAGE_TYPE_ISCSI   = 3

storageTypes_e = {
    'nfs' : STORAGE_TYPE_NFS,
    'fcp' : STORAGE_TYPE_FCP,
    'iscsi' : STORAGE_TYPE_ISCSI
}

ATTACHED   = 'Attached'
UNATTACHED = 'Unattached'
ACTIVE     = 'Active'
INACTIVE   = 'Inactive'

DATA_DOMAIN   = 1
ISO_DOMAIN    = 2
BACKUP_DOMAIN = 3

BLANK_UUID = '00000000-0000-0000-0000-000000000000'

COLORS = {"default":0, "black":30, "red":31, "green":32, "yellow":33,
    "blue":34,"magenta":35, "cyan":36, "white":37, "black":38, "black":39}

__commonTemplate__ = {
    'common'  : {
    'testDebug'    : {'default' : 1},
    'qadb'         : {'default' : 0},
    'dcNamePref'   : {'default' : 'UT_DC_'},
    'vds1'         : {},
    'storageType'  : {'default' : 'nfs'},
    'qaSetup'      : {'default' : 'yellow'},
    'buildName'    : {'default' : 'trunk'}
    },
    'iso'     : { 'connection' : {} },
    'backup'  : { 'type' : {}, 'connection' : {} }
}
__nfsTemplate__ = {
    'nfs1' : { 'connection' : {} },
    'nfs2' : { 'connection' : {} },
    'nfs3' : { 'connection' : {} }
}
__fcpTemplate__ = {
    'fcp1' : { 'dev' : {} },
    'fcp2' : { 'dev' : {} }
}
__iscsiConn__ = {
    'connection' : {},
    'port'       : {'default' : 3260},
    'iqn'        : {},
    'portal'     : {'default' : 1},
    'user'       : {'default' : ""},
    'password'   : {'default' : ""}
}
__iscsiTemplate__ = {
    'iscsi1' : __iscsiConn__,
    'iscsi2' : __iscsiConn__
}


def writeLog(line, log_file='', debug = 0, color = ''):
    line = time.strftime("%d/%m/%Y %H:%M:%S") + ' | ' + line
    old_line = line
    if (re.search("error", line, re.IGNORECASE)):
        line = set_color(line, 'red')
    if color != '':
        line = set_color(line, color)
    if debug:
        print line

    #restore line without color chars(for Windows readers)
    line = old_line
    if(log_file != ''):
        try:
            log_fp = open(log_file,'a+')
            line = '\n' + line
            log_fp.write(line)
            log_fp.close()
        except:
            print "ERROR: error writing to file '" + log_file + "'!"
            return False
    return True

def set_color (string, new_color):
    if new_color in COLORS:
        color_string = "\033[%dm\033[1m" % COLORS[new_color]  #33[%colors%m
        string = color_string + string + '\033[0m'
    return string

#------------------------------------------------------------------------------
class VDSClient_accessory(vdsc.VDSClient, vdst.BasicVDSTest):

    def __init__(self, logFile = '', debug = 0):
        vdsc.VDSClient.__init__(self)
        self.logFile = logFile
        self.debug = debug

    def setUp(self, uri):
        self.setURI(uri)

    def __log__(self, msg):
        writeLog(msg, self.logFile, self.debug)

    def getVdsCap(self):
        return self.assertVdscOK(self.getVdsCapabilities())['info']

    def waitForTaskFinish(self, taskID, timeout = 300):
        try:
            resp = self.waitForTask(taskID, timeout)
        except Exception,e:
            self.__log__("ERROR waiting for task:" + str(e))
            return False
        self.assertVdscOK(self.clearTask(taskID))

    def getPoolUuidByName(self, name):
        msg = self.assertVdscOK(self.getConnectedStoragePoolsList())
        for spUuid in msg['poollist']:
            msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
            if msg['info']['name'] == name:
                return spUuid
        return False

    def getPoolDomains(self, spUuid):
        return self.assertVdscOK(self.getStorageDomainsList())['domlist']

    def getPoolMasterDomain(self, spUuid):
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
        for sdUuid in msg['dominfo'].keys():
            resp = self.assertVdscOK(self.getStorageDomainInfo(sdUuid))
            if resp['info']['role'] == 'Master':
                return sdUuid
        self.__log__("Master domain is not found in pool %s!" % spUuid)
        return False

    def getPoolIsoDomain(self, spUuid):
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
        for sdUuid in msg['dominfo'].keys():
            resp = self.assertVdscOK(self.getStorageDomainInfo(sdUuid))
            if resp['info']['class'] == 'Iso':
                return sdUuid
        self.__log__("Iso domain is not found in pool %s!" % spUuid)
        return False

    def getPoolExportDomain(self, spUuid):
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
	for sdUuid in msg['dominfo'].keys():
            resp = self.assertVdscOK(self.getStorageDomainInfo(sdUuid))
            if resp['info']['class'] == 'Backup':
		return sdUuid
        self.__log__("Export domain is not found in pool %s!" % spUuid)
	return False

    def getDeviceByConnection(self, connection):
        msg = self.assertVdscOK(self.getDeviceList())
        for pvInfo in msg['devList']:
            for path in pvInfo['pathlist']:
                if path['iqn'] == connection['iqn']:
                    return True, pvInfo['GUID']
        return False, ''

    def addDomainToStoragePool(self, spUuid, storageType, domainType, domainName, storageParam):
        self.__log__("Add domain to the storage pool %s" % spUuid)
        self.assertTrue(self.connectStorage(storageType, [storageParam]))
        storageDev = None
        if storageType == STORAGE_TYPE_NFS:
            storageDev = storageParam['connection']
        else:
            if storageType == STORAGE_TYPE_ISCSI:
                rc, dev = self.getDeviceByConnection(storageParam)
                self.assertTrue(rc, "Storage device GUID is not found!")
            else:
                dev = storageParam['dev']
            vgUuid = self.newUUID()
            msg = self.assertVdscOK(self.createVG(vgUuid, [dev]))
            storageDev = msg['uuid']

        sdUuid = self.newUUID()
        self.assertVdscOK(self.createStorageDomain(storageType, sdUuid, domainName, storageDev, domainType))
        self.assertVdscOK(self.attachStorageDomain(sdUuid, spUuid))
        self.assertVdscOK(self.activateStorageDomain(sdUuid, spUuid))
        return True

    def removeDomainFromPool(self, spUuid, sdType, sdUuid, storageParam):
        self.__log__("Remove domain %s from the storage pool %s" % (sdUuid, spUuid))
        self.assertTrue(self.changeDomainStatus(sdUuid, spUuid, INACTIVE))
        self.assertTrue(self.changeDomainStatus(sdUuid, spUuid, UNATTACHED))
        vgUuid = None
        if sdType == STORAGE_TYPE_ISCSI or sdType == STORAGE_TYPE_FCP:
            resp = self.assertVdscOK(self.getStorageDomainInfo(sdUuid))
            vgUuid = resp['info']['vguuid']
        self.assertVdscOK(self.formatStorageDomain(sdUuid))
        if vgUuid:
            self.assertVdscOK(self.removeVG(vgUuid))
        self.assertTrue(self.disconnectStorage(sdType, [storageParam]))
        return True

    def getPoolMasterVersion(self, spUuid):
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
        return int(msg['info']['master_ver'])

    def checkPoolInfo(self, spName):
        spUuid = self.getPoolUuidByName(spName)
        spDomains = self.getPoolDomains(spUuid)
        if not spUuid or not spDomains:
            return False
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
        spInfoDomains = re.split(',', msg['info']['domains'])
        spInfoDomains.sort()
        spDomains.sort()
        sdCnt = len(spDomains)
        if len(spInfoDomains) != sdCnt:
            self.__log__("ERROR: count of domains in pool info is wrong!")
            return False
        for i in range (0,sdCnt-1):
            domInfo = re.split(':', spInfoDomains[i])
            if spDomains[i] != domInfo[0]: #uuid
                self.__log__("ERROR: list of domains in pool is wrong!")
                return False
        return True

    def checkDomainStatus(self, sdUuid, spUuid, expectedStatus):
        msg = self.assertVdscOK(self.getStoragePoolInfo(spUuid))
        sdStatus = ''
        try:
            sdStatus = msg['info']['domains'][sdUuid]['status']
        except:
            if expectedStatus == UNATTACHED:
                self.__log__("INFO: Storage pool doesn't contain domain " + sdUuid)
                return True
            else:
                self.__log__("ERROR: Storage pool doesn't contain domain " + sdUuid)
                return False
        if sdStatus != expectedStatus:
            self.__log__("ERROR: Domain status is wrong: " + sdStatus)
            return False
        return True

    def changeDomainStatus(self, sdUuid, spUuid, newStatus, masterSdUuid = ''):
        mVer = self.getPoolMasterVersion(spUuid)
        if newStatus == ACTIVE:
            self.assertVdscOK(self.activateStorageDomain(sdUuid, spUuid))
        elif newStatus == INACTIVE:
            if masterSdUuid != '':
                self.assertVdscOK(self.deactivateStorageDomain(sdUuid, spUuid, masterSdUuid, mVer+1))
            else:
                self.assertVdscOK(self.deactivateStorageDomain(sdUuid, spUuid, BLANK_UUID, mVer))
        elif newStatus == ATTACHED:
            self.assertVdscOK(self.attachStorageDomain(sdUuid, spUuid))
        elif newStatus == UNATTACHED:
            if masterSdUuid != '':
                self.assertVdscOK(self.detachStorageDomain(sdUuid, spUuid, masterSdUuid, mVer))
            else:
                self.assertVdscOK(self.detachStorageDomain(sdUuid, spUuid, BLANK_UUID, mVer))

        if newStatus == INACTIVE:
            newStatus = ATTACHED
        #return self.checkDomainStatus(sdUuid, spUuid, newStatus)
        return True

    def connectStorage(self, spType, connList):
        if spType == STORAGE_TYPE_FCP:
            return True
        for conn in connList:
            conn['id'] = self.newUUID()
            self.assertVdscOK(self.connectStorageServer(spType, BLANK_UUID, [conn]))
        return True

    def disconnectStorage(self, spType, connList):
        if spType == STORAGE_TYPE_FCP:
            return True
        for conn in connList:
            conn['id'] = self.newUUID()
            self.assertVdscOK(self.disconnectStorageServer(spType, BLANK_UUID, [conn]))
        return True

    def createVGList(self, connList = [], deviceList = []):
        vgList = []
        listDevIn = []
        if len(deviceList) == 0:
            msg = self.assertVdscOK(self.getDeviceList())
            for pvInfo in msg['devList']:
                createFlag = False
                for path in pvInfo['pathlist']:
                    for conn in connList:
                        if path['connection'] == conn['connection'] and pvInfo['vgUUID'] == '':
                            createFlag = True
                            break
                if createFlag == True:
                    listDevIn.append(pvInfo['GUID'])
        else:
            for dev in deviceList:
                listDevIn.append(dev['dev'])
        if len(listDevIn) == 0:
            self.__log__("ERROR: no physical volumes to create VGs!")
            return False, vgList
        for pvGuid in listDevIn:
            vgUuid = self.newUUID()
            msg = self.assertVdscOK(self.createVG(vgUuid, [pvGuid]))
            vgList.append(msg['uuid'])
        return True, vgList

    def getVGUuidList(self):
        msg = self.assertVdscOK(self.getVGList())
        vgUuidList = []
        for entry in msg['vglist']:
            for element in entry.keys():
                if element == 'vgUUID':
                    vgUuidList.append(entry[element])
        return True, vgUuidList

    def createSP(self, spType, spName, dataStorageList = [], isoStorage = None):
        """
        Connect storage, create Storage Domain(-s), create Storage Pool and start SPM
        """
        sdUuidList = []
        sdMaster = ''
        sdNamePref = spName + '_domain_'
        ind = 1

        #connect storage
        self.assertTrue(self.connectStorage(spType, dataStorageList))
        if isoStorage:
            self.assertTrue(self.connectStorage(STORAGE_TYPE_NFS, [isoStorage]))

        #get VG list for SAN storage
        dataStorageListRes = []
        if spType == STORAGE_TYPE_NFS:
            for conn in dataStorageList:
                dataStorageListRes.append(conn['connection'])
        else:
            if spType == STORAGE_TYPE_ISCSI:
                connList = dataStorageList
                devList = []
            elif spType == STORAGE_TYPE_FCP:
                connList = []
                devList = dataStorageList
            time.sleep(2)
            rc, dataStorageListRes = self.createVGList(connList, devList)
            if not rc or len(dataStorageListRes) == 0:
                self.__log__("ERROR: No VGs to create storage domains!")
                return False

        #create data Storage Domains
        for conn in dataStorageListRes:
            sdName = sdNamePref + str(ind)
            sdUuid = self.newUUID()
            self.assertVdscOK(self.createStorageDomain(spType, sdUuid, sdName, conn, DATA_DOMAIN))
            sdUuidList.append(sdUuid)
            if sdMaster == '':
                sdMaster = sdUuid
            ind += 1

        if isoStorage:
            #create ISO Storage Domain
            sdName = 'ISO'
            sdUuid = self.newUUID()
            self.assertVdscOK(self.createStorageDomain(STORAGE_TYPE_NFS, sdUuid, sdName, isoStorage['connection'], ISO_DOMAIN))
            sdUuidList.append(sdUuid)

        #create Storage Pool
        spUuid = self.newUUID()
        mVer = 1
        self.assertVdscOK(self.createStoragePool(spUuid, spName, sdMaster, sdUuidList, mVer))

        #connect storage pool
        hostId = 1
        self.assertVdscOK(self.connectStoragePool(spUuid, hostId, 'scsi_key'))

        #start SPM
        msg = self.assertVdscOK(self.spmStart(spUuid, -1, -1, 0, 'False'))
        self.waitForTaskFinish(msg['uuid'])

        #activate Storage Domains
        for sdUuid in sdUuidList:
            self.assertVdscOK(self.activateStorageDomain(sdUuid, spUuid))

        #from this point Storage Pool is ready
        return True

    def removeSP(self, spType, spName, connectionList = [], isoStorage = None, flag = 'removeVG'):
        """
        Detach Storage Domain(-s), destroy Storage Pool and disconnect storage
        """
        sdList = False
        spUuid = self.getPoolUuidByName(spName)
        if spUuid:
            sdList = self.getPoolDomains(spUuid)
            if sdList:
                sdMaster = self.getPoolMasterDomain(spUuid)
                if sdMaster:
                    sdList.remove(sdMaster)
                    sdList.append(sdMaster)
        #detach SDs
        mVer = self.getPoolMasterVersion(spUuid)
        if sdList and spUuid:
            for sd in sdList:
                self.assertVdscOK(self.deactivateStorageDomain(sd, spUuid, BLANK_UUID, mVer))
                if sd != sdMaster:
                    self.assertVdscOK(self.detachStorageDomain(sd, spUuid, BLANK_UUID, mVer))
        #destroy SP
        if spUuid:
            hostId = 1
            self.assertVdscOK(self.destroyStoragePool(spUuid, hostId, 'scsi_key'))
        #format SDs
        if sdList:
            for sd in sdList:
                self.assertVdscOK(self.formatStorageDomain(sd))
        #remove VGs
        if (spType == STORAGE_TYPE_ISCSI or spType == STORAGE_TYPE_FCP) and flag == 'removeVG':
            rc, vgUuidList = self.getVGUuidList()
            if rc:
                for vg in vgUuidList:
                    self.assertVdscOK(self.removeVG(vg))
        #disconnect storage
        self.assertTrue(self.disconnectStorage(spType, connectionList))
        if isoStorage:
            self.assertTrue(self.disconnectStorage(STORAGE_TYPE_NFS, [isoStorage]))

        return True


